<!DOCTYPE html><html lang="en" data-beasties-container><head>
  <meta charset="UTF-8">
  <title>Django and MongoDB Connector Design</title>
  <meta name="description" content="Djongo is a smarter approach to database querying. It maps python objects to MongoDB documents.
         It is popularly referred to as an Object Document Mapper or ODM.
         It is an extension to the traditional Django object relational modeling framework.
         Use Django Admin to directly add and modify documents stored in MongoDB.
         Use other contrib modules such as Auth and Sessions without any changes.">
  <meta name="keywords" content="Django, MongoDB, Django MongoDB connector, Object document mapper">
  <meta property="og:type" content="website">
  <meta property="og:locale" content="en_US">
  <meta property="og:site_name" content="Djongomapper">
  <meta property="og:title" content="Djongo">
  <meta property="og:url" content="https://www.djongomapper.com/">
  <meta property="og:description" content="Djongo is a smarter approach to database querying. It maps python objects to MongoDB documents. It is popularly referred to as an Object Document Mapper or ODM. It is an extension to the traditional Django object relational modeling framework. Use Django Admin to directly add and modify documents stored in MongoDB. Use other contrib modules such as Auth and Sessions without any changes.">
  <link rel="canonical" href="https://www.djongomapper.com/">
  <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "Organization",
      "name": "Doableware",
      "url": "https://www.djongomapper.com/",
      "logo": "/assets/images/djongo-symbol-small.png"
    }
  </script>
  <meta name="google-site-verification" content="tFNu7Nc9hzKF9v7f6kYaoMbBCNyGREchcKMVdxJuyJo">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="preload" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5/css/all.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
  <noscript>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5/css/all.min.css">
  </noscript>
  <link rel="stylesheet" type="text/css" media="screen" href="/assets/css/styles.css">
  <link rel="shortcut icon" href="/assets/images/favicon.ico">
  <script>
    if (window.location.hostname != 'localhost') {
      (function (w, d, s, l, i) {
        w[l] = w[l] || [];
        w[l].push({
                    'gtm.start':
                      new Date().getTime(), event: 'gtm.js'
                  });
        var f = d.getElementsByTagName(s)[0],
          j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : '';
        j.async = true;
        j.src =
          'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
        f.parentNode.insertBefore(j, f);
      })(window, document, 'script', 'dataLayer', 'GTM-T72KG6N');
    }
  </script>
  <base href="/">
<link rel="stylesheet" href="styles-JF5ME2K6.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles-JF5ME2K6.css"></noscript><style ng-app-id="ng">.cookie-notice[_ngcontent-ng-c2830357685]{height:0}.open[_ngcontent-ng-c2830357685]{height:auto}.close[_ngcontent-ng-c2830357685]{height:0;transition:height .3s ease-out}.mast[_ngcontent-ng-c2830357685]{position:sticky;top:0;padding:.5em 0;z-index:10;background:#fff;border-bottom:1px solid rgb(241.7553,242.60496,243.2547)}@media (max-width: 90rem){.mast[_ngcontent-ng-c2830357685]{padding:.5em 1em}}.mast[_ngcontent-ng-c2830357685] > div[_ngcontent-ng-c2830357685]{margin:0 auto;max-width:80rem;display:flex;flex-direction:row;justify-content:space-between}.mast[_ngcontent-ng-c2830357685]   a[_ngcontent-ng-c2830357685]{display:block;color:#62696e;text-decoration:none}.mast[_ngcontent-ng-c2830357685]   .mast-logo[_ngcontent-ng-c2830357685]{display:flex;gap:var(--space-xs);align-items:center}.mast[_ngcontent-ng-c2830357685]   .mast-logo[_ngcontent-ng-c2830357685]   img[_ngcontent-ng-c2830357685]{max-height:2em}.mast[_ngcontent-ng-c2830357685]   .mast-nav[_ngcontent-ng-c2830357685]   ul[_ngcontent-ng-c2830357685]{display:flex;align-items:center;gap:var(--space-md)}.mast[_ngcontent-ng-c2830357685]   .mast-nav[_ngcontent-ng-c2830357685]   ul.media-small[_ngcontent-ng-c2830357685]{padding-top:var(--space-sm);padding-bottom:var(--space-sm);flex-direction:column;align-items:start;gap:var(--space-xs)}.mast[_ngcontent-ng-c2830357685]   .mast-nav[_ngcontent-ng-c2830357685]   .nav-link[_ngcontent-ng-c2830357685]{position:relative}.mast[_ngcontent-ng-c2830357685]   .mast-nav[_ngcontent-ng-c2830357685]   .nav-link[_ngcontent-ng-c2830357685]:hover:after{width:100%}.mast[_ngcontent-ng-c2830357685]   .mast-nav[_ngcontent-ng-c2830357685]   .nav-link[_ngcontent-ng-c2830357685]:after{content:"";position:absolute;left:50%;bottom:0;transform:translate(-50%);width:0;height:4px;background-color:#62696e;transition:width .2s ease-in-out}.mast[_ngcontent-ng-c2830357685]   .mast-nav[_ngcontent-ng-c2830357685]   .btn-nav[_ngcontent-ng-c2830357685]{padding:.5em 1em;font-size:var(--font-sm);font-weight:700;text-align:center;border-width:0;border-radius:.1875em;color:#fff}.burger[_ngcontent-ng-c2830357685]{display:flex;flex-direction:column;gap:4px}.burger[_ngcontent-ng-c2830357685] > div[_ngcontent-ng-c2830357685]{height:4px;width:var(--space-md);background-color:#62696e;border-radius:4px}.burger[_ngcontent-ng-c2830357685]:hover{cursor:pointer}</style><style ng-app-id="ng">.media-small[_ngcontent-ng-c40719357]{position:fixed;top:3rem;left:0;padding:0 var(--space-sm);background:#fff;height:100vh;border-right:1px solid rgb(241.7553,242.60496,243.2547);z-index:1}.cross[_ngcontent-ng-c40719357]{margin:var(--space-2xs) 0;aspect-ratio:1;width:var(--font-md)}.cross[_ngcontent-ng-c40719357]:hover{cursor:pointer}.cross[_ngcontent-ng-c40719357] > div[_ngcontent-ng-c40719357]{background:#000;height:1px;width:var(--font-md)}.cross[_ngcontent-ng-c40719357] > div[_ngcontent-ng-c40719357]:nth-child(1){transform:translateY(calc(var(--font-md) * .5)) rotate(-45deg)}.cross[_ngcontent-ng-c40719357] > div[_ngcontent-ng-c40719357]:nth-child(2){transform:translateY(calc(var(--font-md) * .5 - 1px)) rotate(45deg)}.open[_ngcontent-ng-c40719357]{transition:transform .4s ease-in;transform:translate(0)}.close[_ngcontent-ng-c40719357]{transform:translate(-100%);padding:0;overflow:hidden;transition:transform .3s ease-out}</style><style ng-app-id="ng">.body[_ngcontent-ng-c2001800090]{display:grid;grid-template-columns:minmax(max-content,calc(16rem - 1em)) minmax(16rem,80rem) minmax(min-content,calc(16rem - 1em)) max-content;grid-template-rows:repeat(2,auto);grid-template-areas:"aside-left page-content aside-right aside-right-2" ".          page-content .           .";justify-content:center;column-gap:1em;padding-left:1em;padding-right:1em}.page-content[_ngcontent-ng-c2001800090]{grid-area:page-content}.aside-left[_ngcontent-ng-c2001800090]{grid-area:aside-left}.aside-right[_ngcontent-ng-c2001800090]{grid-area:aside-right}.aside-right-2[_ngcontent-ng-c2001800090]{grid-area:aside-right-2}.aside-right-2[_ngcontent-ng-c2001800090]{display:flex;align-items:flex-end}.aside-right-2[_ngcontent-ng-c2001800090]   ul[_ngcontent-ng-c2001800090]{display:flex;flex-direction:column;gap:.5em}.btn-nav[_ngcontent-ng-c2001800090]{font-weight:400;margin-bottom:0}@media (max-width: 80rem){.body[_ngcontent-ng-c2001800090]{grid-template-columns:max-content minmax(24rem,80rem);grid-template-rows:repeat(3,auto);grid-template-areas:"aside-left aside-right-2" "aside-left aside-right" "aside-left page-content"}.aside-right-2[_ngcontent-ng-c2001800090]   ul[_ngcontent-ng-c2001800090]{flex-direction:row}}@media (max-width: 48rem){.aside-right-2[_ngcontent-ng-c2001800090]{flex-direction:row}}.nav[_ngcontent-ng-c2001800090]{padding-top:1em;padding-bottom:1em;min-width:min-content;max-width:max-content;font-size:var(--font-sm)}@media (max-width: 80rem){.nav[_ngcontent-ng-c2001800090]{font-size:var(--font-base)}}.nav[_ngcontent-ng-c2001800090]   a[_ngcontent-ng-c2001800090]{text-decoration:none}.nav-sticky[_ngcontent-ng-c2001800090]{position:sticky;top:3em;overflow:auto;height:calc(100vh - 3em)}.nav-sticky.aside-left[_ngcontent-ng-c2001800090]{z-index:1}@media (max-width: 80rem){.nav-sticky.aside-right[_ngcontent-ng-c2001800090], .nav-sticky.aside-right-2[_ngcontent-ng-c2001800090]{position:static;height:inherit}}.nav-side[_ngcontent-ng-c2001800090]{line-height:1.58}.nav-side[_ngcontent-ng-c2001800090]   h3[_ngcontent-ng-c2001800090]{font-size:1em;opacity:.7;text-transform:uppercase;border-bottom:1px solid rgb(241.7553,242.60496,243.2547);margin:.5em 0;padding:.25em 0}.nav-side[_ngcontent-ng-c2001800090]   a[_ngcontent-ng-c2001800090]{color:inherit;opacity:.7}.nav-side[_ngcontent-ng-c2001800090]   .active[_ngcontent-ng-c2001800090]{font-weight:700;opacity:1}.nav-side[_ngcontent-ng-c2001800090]   a[_ngcontent-ng-c2001800090]:hover{opacity:1}.nav-toc[_ngcontent-ng-c2001800090]   h3[_ngcontent-ng-c2001800090]{font-size:var(--font-base);font-weight:700;color:#fff;background:#62696e;border-top-left-radius:.375em;border-top-right-radius:.375em;padding:var(--space-2xs) var(--space-xs);margin:0}.nav-toc[_ngcontent-ng-c2001800090]   a[_ngcontent-ng-c2001800090]{display:block;padding:var(--space-2xs) var(--space-xs);color:#646769;font-weight:700;line-height:1.5;border-bottom:1px solid rgb(241.7553,242.60496,243.2547);border-left:1px solid rgb(241.7553,242.60496,243.2547);border-right:1px solid rgb(241.7553,242.60496,243.2547)}.nav-toc[_ngcontent-ng-c2001800090]   a[_ngcontent-ng-c2001800090]:hover{text-decoration:underline}.nav-toc[_ngcontent-ng-c2001800090]   li[_ngcontent-ng-c2001800090]   li[_ngcontent-ng-c2001800090] > a[_ngcontent-ng-c2001800090]{font-weight:400;padding-left:1em}.nav-toc[_ngcontent-ng-c2001800090]   .active[_ngcontent-ng-c2001800090]{background-color:#e2e4e5}.page-content[_ngcontent-ng-c2001800090]{margin-top:1em}</style></head>
<body><!--nghm--><script type="text/javascript" id="ng-event-dispatch-contract">(()=>{function p(t,n,r,o,e,i,f,m){return{eventType:t,event:n,targetElement:r,eic:o,timeStamp:e,eia:i,eirp:f,eiack:m}}function u(t){let n=[],r=e=>{n.push(e)};return{c:t,q:n,et:[],etc:[],d:r,h:e=>{r(p(e.type,e,e.target,t,Date.now()))}}}function s(t,n,r){for(let o=0;o<n.length;o++){let e=n[o];(r?t.etc:t.et).push(e),t.c.addEventListener(e,t.h,r)}}function c(t,n,r,o,e=window){let i=u(t);e._ejsas||(e._ejsas={}),e._ejsas[n]=i,s(i,r),s(i,o,!0)}window.__jsaction_bootstrap=c;})();
</script><script>window.__jsaction_bootstrap(document.body,"ng",["click"],[]);</script>
<app-root ng-version="20.1.4" _nghost-ng-c2830357685 ngh="3" ng-server-context="ssg"><div _ngcontent-ng-c2830357685 class="page-splash"><div _ngcontent-ng-c2830357685 class="mast"><div _ngcontent-ng-c2830357685><div _ngcontent-ng-c2830357685 class="mast-logo"><a _ngcontent-ng-c2830357685 href="/"><img _ngcontent-ng-c2830357685 src="/assets/images/djongo-symbol-small.png" alt="Djongo"></a><!----></div><div _ngcontent-ng-c2830357685 class="mast-nav"><app-nav _ngcontent-ng-c2830357685 _nghost-ng-c40719357 ngh="0"><!----><!----><!----></app-nav></div></div></div><div _ngcontent-ng-c2830357685 class="initial-content"><router-outlet _ngcontent-ng-c2830357685></router-outlet><ng-component _nghost-ng-c2001800090 ngh="2"><div _ngcontent-ng-c2001800090 class="body"><aside _ngcontent-ng-c2001800090 class="nav-sticky aside-left"><app-nav _ngcontent-ng-c2001800090 _nghost-ng-c40719357 ngh="0"><!----><!----><!----></app-nav></aside><div _ngcontent-ng-c2001800090 class="page-content"><header _ngcontent-ng-c2001800090><h1 _ngcontent-ng-c2001800090 class="title-docs">Django and MongoDB Connector Design</h1></header><router-outlet _ngcontent-ng-c2001800090></router-outlet><django-and-mongodb-connector-design-2 class="0" ngh="1"><h2 id="sql-to-mongodb-query-mapping">SQL to MongoDB query mapping.</h2><table><thead><tr><th>SQL query</th><th>pymongo API</th></tr></thead><tbody><tr><td>SELECT</td><td>find(projection=)</td></tr><tr><td>WHERE</td><td>find(filter=)</td></tr><tr><td>AND</td><td>$and</td></tr><tr><td>OR</td><td>$or</td></tr><tr><td>NOT</td><td>$neq</td></tr><tr><td>IN</td><td>$in</td></tr><tr><td>INNER JOIN</td><td>find(), find(), find()</td></tr><tr><td>LEFT JOIN</td><td>aggregate($lookup)</td></tr><tr><td>UPDATE</td><td>update_many</td></tr><tr><td>DELETE</td><td>delete_many</td></tr><tr><td>INSERT INTO</td><td>insert_many</td></tr><tr><td>CREATE DATABASE</td><td>implicit</td></tr><tr><td>ALTER DATABASE</td><td>implicit</td></tr><tr><td>CREATE TABLE</td><td>implicit</td></tr><tr><td>ALTER TABLE</td><td>implicit</td></tr><tr><td>DROP TABLE</td><td>drop_collection</td></tr><tr><td>CREATE INDEX</td><td>create_indexes</td></tr><tr><td>DROP INDEX</td><td>drop_index</td></tr></tbody></table><h2 id="performing-relational-sql-joins-in-mongodb">Performing relational SQL JOINs in MongoDB</h2><p>Since MongoDB does not have an intrinsic JOIN command the multi-collection JOIN must be done at the application layer. Due to the intrinsic design of MongoDB, if a parallel thread does an update operation on the <strong>same set of documents</strong> on which JOIN is taking place, there is a possibility of getting different results than expected. This possibility exists in multi-threaded SQL implementations as well. </p><p>Application layer multi-collection JOINS without any interleaved database updates are thread safe and can be done in MongoDB. In case you feel SQL joins confusing there is an excellent explanation on how <a href="https://www.interfacett.com/blogs/multiple-joins-work-just-like-single-joins/">sql joins work</a> which can be referred to before proceeding further. </p><p>Here is an example of a typical SQL query generated by Django admin while modifying a user property.</p><div appcodecopy class="codehilite"><pre><span></span><code><span class="k">SELECT</span><span class="w"> </span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"id"</span><span class="p">,</span><span class="w"> </span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"name"</span><span class="p">,</span><span class="w"> </span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"content_type_id"</span><span class="p">,</span><span class="w"> </span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"codename"</span><span class="p">,</span><span class="w"> </span><span class="ss">"django_content_type"</span><span class="p">.</span><span class="ss">"id"</span><span class="p">,</span><span class="w"> </span><span class="ss">"django_content_type"</span><span class="p">.</span><span class="ss">"app_label"</span><span class="p">,</span><span class="w"> </span><span class="ss">"django_content_type"</span><span class="p">.</span><span class="ss">"model"</span><span class="w"> </span>
<span class="k">FROM</span><span class="w"> </span><span class="ss">"auth_permission"</span><span class="w"> </span>
<span class="k">INNER</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="ss">"django_content_type"</span><span class="w"> </span>
<span class="w">    </span><span class="k">ON</span><span class="w"> </span><span class="p">(</span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"content_type_id"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ss">"django_content_type"</span><span class="p">.</span><span class="ss">"id"</span><span class="p">)</span><span class="w"> </span>
<span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span>
<span class="w">    </span><span class="ss">"django_content_type"</span><span class="p">.</span><span class="ss">"app_label"</span><span class="w"> </span><span class="k">ASC</span><span class="p">,</span><span class="w"> </span>
<span class="w">    </span><span class="ss">"django_content_type"</span><span class="p">.</span><span class="ss">"model"</span><span class="w"> </span><span class="k">ASC</span><span class="p">,</span><span class="w"> </span>
<span class="w">    </span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"codename"</span><span class="w"> </span><span class="k">ASC</span>
</code></pre><img alt="copy code" src="/assets/images/copy.svg" class="docs-copy"></div><p>INNER JOIN translates to:</p><div appcodecopy class="highlighter-rouge highlight codehilite"><pre><span></span><code><span class="n">docs</span> <span class="o">=</span> <span class="n">db</span><span class="p">[</span><span class="s1">'auth_permission'</span><span class="p">]</span><span class="o">.</span><span class="n">find</span><span class="p">(</span>
    <span class="p">{},</span>
    <span class="p">{</span><span class="s1">'content_type_id'</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">'_id'</span><span class="p">:</span> <span class="kc">False</span><span class="p">}</span>
<span class="p">)</span><span class="o">.</span><span class="n">to_list</span><span class="p">()</span>

<span class="n">joined_docs</span> <span class="o">=</span> <span class="n">db</span><span class="p">[</span><span class="s1">'django_content_type'</span><span class="p">]</span><span class="o">.</span><span class="n">find</span><span class="p">(</span>
    <span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'$in'</span><span class="p">:</span> <span class="p">[</span><span class="n">doc</span><span class="p">[</span><span class="s1">'content_type_id'</span><span class="p">]</span> <span class="k">for</span> <span class="n">doc</span> <span class="ow">in</span> <span class="n">docs</span><span class="p">]}},</span>
    <span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">'_id'</span><span class="p">:</span> <span class="kc">False</span><span class="p">}</span>
<span class="p">)</span><span class="o">.</span><span class="n">to_list</span><span class="p">()</span>

<span class="c1"># Finally, project the SELECTed fields with content_type_id in joined_docs</span>
</code></pre><img alt="copy code" src="/assets/images/copy.svg" class="docs-copy"></div><p>So INNER JOIN can basically be done using three application level find operations out of which 2 are for lookups.</p><p>Consider a complex multi-join SQL query</p><div appcodecopy class="codehilite"><pre><span></span><code><span class="k">SELECT</span><span class="w"> </span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"id"</span><span class="p">,</span><span class="w"> </span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"name"</span><span class="p">,</span><span class="w"> </span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"content_type_id"</span><span class="p">,</span><span class="w"> </span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"codename"</span><span class="w"> </span>
<span class="k">FROM</span><span class="w"> </span><span class="ss">"auth_permission"</span><span class="w"> </span>
<span class="k">INNER</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="ss">"auth_user_user_permissions"</span><span class="w"> </span>
<span class="w">    </span><span class="k">ON</span><span class="w"> </span><span class="p">(</span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"id"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ss">"auth_user_user_permissions"</span><span class="p">.</span><span class="ss">"permission_id"</span><span class="p">)</span><span class="w"> </span>
<span class="k">INNER</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="ss">"django_content_type"</span><span class="w"> </span>
<span class="w">    </span><span class="k">ON</span><span class="w"> </span><span class="p">(</span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"content_type_id"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ss">"django_content_type"</span><span class="p">.</span><span class="ss">"id"</span><span class="p">)</span><span class="w"> </span>
<span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span>
<span class="w">    </span><span class="ss">"django_content_type"</span><span class="p">.</span><span class="ss">"app_label"</span><span class="w"> </span><span class="k">ASC</span><span class="p">,</span><span class="w"> </span>
<span class="w">    </span><span class="ss">"django_content_type"</span><span class="p">.</span><span class="ss">"model"</span><span class="w"> </span><span class="k">ASC</span><span class="p">,</span><span class="w"> </span>
<span class="w">    </span><span class="ss">"auth_permission"</span><span class="p">.</span><span class="ss">"codename"</span><span class="w"> </span><span class="k">ASC</span>
</code></pre><img alt="copy code" src="/assets/images/copy.svg" class="docs-copy"></div><p>This can be performed using 4 lookups inside python.</p><div appcodecopy class="highlighter-rouge highlight codehilite"><pre><span></span><code><span class="n">docs</span> <span class="o">=</span> <span class="n">db</span><span class="p">[</span><span class="s1">'auth_permission'</span><span class="p">]</span><span class="o">.</span><span class="n">find</span><span class="p">(</span>
    <span class="p">{},</span>
    <span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">'_id'</span><span class="p">:</span> <span class="kc">False</span><span class="p">}</span>
<span class="p">)</span><span class="o">.</span><span class="n">to_list</span><span class="p">()</span>

<span class="n">joined_docs</span> <span class="o">=</span> <span class="n">db</span><span class="p">[</span><span class="s1">'auth_user_user_permissions'</span><span class="p">]</span><span class="o">.</span><span class="n">find</span><span class="p">(</span>
    <span class="p">{</span><span class="s1">'permission_id'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'$in'</span><span class="p">:</span> <span class="p">[</span><span class="n">doc</span><span class="p">[</span><span class="s1">'id'</span><span class="p">]</span> <span class="k">for</span> <span class="n">doc</span> <span class="ow">in</span> <span class="n">docs</span><span class="p">]}},</span>
    <span class="p">{</span><span class="s1">'permission_id'</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">'_id'</span><span class="p">:</span> <span class="kc">False</span><span class="p">}</span>
<span class="p">)</span><span class="o">.</span><span class="n">to_list</span><span class="p">()</span>

<span class="n">joined_docs2</span> <span class="o">=</span> <span class="n">db</span><span class="p">[</span><span class="s1">'auth_permission'</span><span class="p">]</span><span class="o">.</span><span class="n">find</span><span class="p">(</span>
    <span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'$in'</span><span class="p">:</span> <span class="p">[</span><span class="n">doc</span><span class="p">[</span><span class="s1">'permission_id'</span><span class="p">]</span> <span class="k">for</span> <span class="n">doc</span> <span class="ow">in</span> <span class="n">joined_docs</span><span class="p">]}},</span>
    <span class="p">{</span><span class="s1">'content_type_id'</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">'_id'</span><span class="p">:</span> <span class="kc">False</span><span class="p">}</span>
<span class="p">)</span><span class="o">.</span><span class="n">to_list</span><span class="p">()</span>

<span class="n">joined_docs3</span> <span class="o">=</span> <span class="n">db</span><span class="p">[</span><span class="s1">'django_content_type'</span><span class="p">]</span><span class="o">.</span><span class="n">find</span><span class="p">(</span>
    <span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'$in'</span><span class="p">:</span> <span class="p">[</span><span class="n">doc</span><span class="p">[</span><span class="s1">'content_type_id'</span><span class="p">]</span> <span class="k">for</span> <span class="n">doc</span> <span class="ow">in</span> <span class="n">joined_docs2</span><span class="p">]}},</span>
    <span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">'_id'</span><span class="p">:</span> <span class="kc">False</span><span class="p">}</span>
<span class="p">)</span><span class="o">.</span><span class="n">to_list</span><span class="p">()</span>

<span class="c1"># Finally, project the SELECTed fields with id in joined_docs3</span>
</code></pre><img alt="copy code" src="/assets/images/copy.svg" class="docs-copy"></div><p>LEFT JOIN or LEFT OUTER JOIN can be done using similar lookup operations.</p></django-and-mongodb-connector-design-2><!----></div><aside _ngcontent-ng-c2001800090 class="nav-sticky aside-right"><nav _ngcontent-ng-c2001800090 class="nav nav-toc"><h3 _ngcontent-ng-c2001800090><i _ngcontent-ng-c2001800090 class="fas fa-file-alt"></i> On This Page</h3><ul _ngcontent-ng-c2001800090><!----></ul></nav></aside><aside _ngcontent-ng-c2001800090 class="nav-sticky aside-right-2"><nav _ngcontent-ng-c2001800090 class="nav"><ul _ngcontent-ng-c2001800090><li _ngcontent-ng-c2001800090><a _ngcontent-ng-c2001800090 class="btn btn-invert btn-green-invert btn-nav" href="/docs/1.3/get-started" jsaction="click:;"> 1.3 </a></li><li _ngcontent-ng-c2001800090><a _ngcontent-ng-c2001800090 class="btn btn-invert btn-green-invert btn-nav" href="/docs/2.0/get-started" jsaction="click:;"> 2.0 </a></li><!----></ul></nav></aside></div></ng-component><!----></div><div _ngcontent-ng-c2830357685 id="footer" class="page-footer"><footer _ngcontent-ng-c2830357685><aside _ngcontent-ng-c2830357685 class="l-fixed-notice cookie-notice open"><p _ngcontent-ng-c2830357685>We use cookies to enhance user experience. You consent to their usage by browsing this site. <button _ngcontent-ng-c2830357685 id="cookie-accept" class="btn btn-green" jsaction="click:;">Accept</button></p></aside><div _ngcontent-ng-c2830357685 class="page-footer-copyright">© 2025 Doableware AB.</div></footer></div></div></app-root>
<script>
  window.ga = function () {
    ga.q.push(arguments)
  };
  ga.q = [];
  ga.l = +new Date;
  ga('create', 'UA-75159067-1', 'auto');
  ga('set', 'anonymizeIp', false);
  ga('send', 'pageview')
</script>
<script src="https://www.google-analytics.com/analytics.js" async></script>
<link rel="modulepreload" href="chunk-7WKV4J2W.js"><link rel="modulepreload" href="chunk-HEUFHRRO.js"><link rel="modulepreload" href="chunk-XPVX74O3.js"><link rel="modulepreload" href="chunk-YECZU7CY.js"><link rel="modulepreload" href="chunk-UZ35QZ23.js"><link rel="modulepreload" href="chunk-FDEVB4XX.js"><script src="polyfills-BUUDEW7V.js" type="module"></script><script src="main-E23G4UPT.js" type="module"></script>
<link rel="modulepreload" href="chunk-ZTGAAWUA.js">

<script id="ng-state" type="application/json">{"__nghData__":[{"t":{"0":"t1","2":"t2","3":"t3"},"c":{"0":[],"2":[],"3":[]}},{},{"d":[3,4,6],"t":{"6":"t21","20":"t22","25":"t23"},"c":{"12":[{"i":"c665340984","r":1}],"20":[],"25":[{"i":"t23","r":1,"x":2}]}},{"t":{"6":"t0","12":"t4"},"c":{"6":[],"14":[{"i":"c2001800090","r":1}]},"d":[9,10,12]}]}</script></body></html>